package com.android.webserver.db;

import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.android.webserver.R;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

/**
 * @author Baptiste GOURDIN
 * 
 */
public class DatabaseOpenHelper extends SQLiteOpenHelper
{

	private static final String	DATABASE_NAME						= "webserver.db";
	private static final int		DATABASE_VERSION				= 2;

	private static final String	APPLICATION_TABLE_NAME	= "application";

	private SQLiteDatabase			dbRead;
	private SQLiteDatabase			dbWrite;
	private boolean							newDb										= false;
	private Context							context;

	public DatabaseOpenHelper(Context context)
	{
		super(context, DATABASE_NAME, null, DATABASE_VERSION);
		dbRead = this.getReadableDatabase();
		dbWrite = this.getWritableDatabase();
		this.context = context;
		Log.d("WebServer", "New DB ? " + newDb);
		if (newDb)
			readConfFile();
	}

	public void close()
	{
		dbRead.close();
		dbWrite.close();
	}

	@Override
	public void onCreate(SQLiteDatabase db)
	{
		initDatabase(db);
		newDb = true;
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
	{
	}

	private void initDatabase(SQLiteDatabase db)
	{
		db
				.execSQL("CREATE TABLE "
						+ APPLICATION_TABLE_NAME
						+ " (name TEXT DEFAULT NULL, path TEXT DEFAULT NULL, provider TEXT DEFAULT NULL, password TEXT DEFAULT '', enabled INTEGER DEFAULT 1, "
						+ "httponly INTEGER DEFAULT 1, serverfilter INTEGER DEFAULT 1, csp INTEGER DEFAULT 1, scsp INTEGER DEFAULT 1, "
						+ "csrf INTEGER DEFAULT 1, originheader INTEGER DEFAULT 1, xframe INTEGER DEFAULT 1, ssl INTEGER DEFAULT 1, "
						+ "hsts INTEGER DEFAULT 1, securecookie INTEGER DEFAULT 1, present INTEGER DEFAULT 0, UNIQUE(path));");
		// db.execSQL("CREATE TABLE "
		// + SESSION_TABLE_NAME
		// + " (webAppId LONG, token TEXT, expire LONG);");

		this.dbWrite = db;
		this.dbRead = db;
	}

	public void registerApplication(WebApplication webApp)
	{
		Cursor c = dbRead.query(APPLICATION_TABLE_NAME, new String[] { "ROWID",  "name"},
				"path=?", new String[] { webApp.getPath() }, null, null, null);

		if (c.getCount() == 0)
			dbWrite.insertOrThrow(APPLICATION_TABLE_NAME, null, webApp
					.getContentValues());
		else
		{
			c.moveToFirst();
			// If name is not set, then the configuration come from the web server configuration file.
			if ((c.getString(1) == null) || (!c.getString(1).equals("")))
			{
				ContentValues cv = new ContentValues();
				cv.put("name", webApp.getName());
				cv.put("provider", webApp.getProvider());
				cv.put("password", webApp.getPassword());
				dbWrite.update(APPLICATION_TABLE_NAME, cv,
						"ROWID=?", new String[] { String.valueOf(c.getLong(0)) });
			}
		}
	}

	public void updateApplication(WebApplication webApp)
	{
		Cursor c = dbRead.query(APPLICATION_TABLE_NAME, new String[] { "ROWID" },
				"path=?", new String[] { webApp.getPath() }, null, null, null);
		c.moveToFirst();
		dbWrite.update(APPLICATION_TABLE_NAME, webApp.getContentValues(),
				"ROWID=?", new String[] { String.valueOf(c.getLong(0)) });
	}

	public WebApplication getWebApplicationFromPath(String path)
	{
		Cursor c = dbRead.query(APPLICATION_TABLE_NAME, WebApplication.select,
				"path=?", new String[] { path }, null, null, null);
		if (c.getCount() != 0)
		{
			c.moveToFirst();
			return new WebApplication(c);
		}
		return null;
	}

	public WebApplication getWebApplicationFromId(Long id)
	{
		Cursor c = dbRead.query(APPLICATION_TABLE_NAME, WebApplication.select,
				"ROWID=?", new String[] { id.toString() }, null, null, null);
		if (c.getCount() != 0)
		{
			c.moveToFirst();
			return new WebApplication(c);
		}
		return null;
	}

	public String getProviderFromPath(String path)
	{
		Log.d("WebServer", "getProviderFromPath " + path);

		String provider = null;
		Cursor c = dbRead.query(APPLICATION_TABLE_NAME,
				new String[] { "provider" }, "path=?", new String[] { path }, null,
				null, null);
		if (c.getCount() != 0)
		{
			c.moveToFirst();
			provider = c.getString(0);
		}
		c.close();
		return provider;
	}

	public Cursor getApplications()
	{
		Cursor c = dbRead.query(APPLICATION_TABLE_NAME, new String[] {
				"ROWID as _id", "name", "path", "enabled" }, "name != ''", null, null, null,
				null);

		return c;
	}

	private void readConfFile()
	{
		try
		{
			DocumentBuilder builder = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder();
			InputStream inputStream = context.getResources().openRawResource(
					R.raw.configuration);
			if (inputStream != null)
			{
				Document c = builder.parse(inputStream);
				NodeList nl = c.getElementsByTagName("WebApp");
				for (int i = 0 ; i < nl.getLength(); i++)
				{
					WebApplication webapp = null; 
					Node appNode = nl.item(i);
					NodeList confNodes = appNode.getChildNodes();
					for (int j = 0 ; j < confNodes.getLength(); j++)
					{
						Node confNode = confNodes.item(j);
						if (confNode.getNodeName().equals("path"))
						{
							webapp = new WebApplication(null, confNode.getFirstChild().getNodeValue(), null);
							Log.d("WebServer", "confNode => " + confNode.getFirstChild().getNodeValue());
						}
						else if (webapp != null)
						{
							if (confNode.getNodeName().equals("Enabled"))
									webapp.setEnabled(confNode.getFirstChild().getNodeValue().equals("1"));
							else if (confNode.getNodeName().equals("Password"))
							{
								if (confNode.getFirstChild() != null)
									webapp.setPassword(confNode.getFirstChild().getNodeValue());
								else
									webapp.setPassword("");
							}
							else if (confNode.getNodeName().equals("HttpOnly"))
								webapp.setHttpOnlyStatus(confNode.getFirstChild().getNodeValue().equals("1"));
							else if (confNode.getNodeName().equals("CSP"))
								webapp.setCspStatus(confNode.getFirstChild().getNodeValue().equals("1"));
							else if (confNode.getNodeName().equals("SCSP"))
								webapp.setScspStatus(confNode.getFirstChild().getNodeValue().equals("1"));
							else if (confNode.getNodeName().equals("CSRF"))
								webapp.setCsrfStatus(confNode.getFirstChild().getNodeValue().equals("1"));
							else if (confNode.getNodeName().equals("OriginHeader"))
								webapp.setOriginHeaderStatus(confNode.getFirstChild().getNodeValue().equals("1"));
							else if (confNode.getNodeName().equals("XFrame"))
								webapp.setXframeStatus(confNode.getFirstChild().getNodeValue().equals("1"));
							else if (confNode.getNodeName().equals("SSL"))
								webapp.setSslStatus(confNode.getFirstChild().getNodeValue().equals("1"));
							else if (confNode.getNodeName().equals("HSTS"))
								webapp.setHstsStatus(confNode.getFirstChild().getNodeValue().equals("1"));
							else if (confNode.getNodeName().equals("SecureCookie"))
								webapp.setSecureCookieStatus(confNode.getFirstChild().getNodeValue().equals("1"));
						}
					}
					if (webapp != null)
						registerApplication(webapp);
				}
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
}
